package com.fujiyuu75.sequent;

import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorGroup;
import ohos.agp.animation.AnimatorProperty;
import ohos.agp.components.Component;
import ohos.agp.components.ComponentContainer;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 给一个布局中的每一个子控件添加动画效果
 */
public class Sequent {
    private List<Component> viewList = new ArrayList<>();
    private final int startOffset;
    private final int duration;
    private final int delay;
    private final Direction direction;
    private AnimatorProperty[] animator;
    private final Animation anim;

    /**
     * 构造器
     */
    public static class Builder {
        private static final int DEFAULT_OFFSET = 100;
        private static final int DEFAULT_DURATION = 500;
        private static final int DEFAULT_DELAY = 0;

        private ComponentContainer vg;
        private int startOffset = DEFAULT_OFFSET;
        private int duration = DEFAULT_DURATION;
        private int delay = DEFAULT_DELAY;
        private Direction direction = Direction.FORWARD;
        private AnimatorProperty[] animator;
        private Animation anim;

        Builder(ComponentContainer vg) {
            this.vg = vg;
        }

        /**
         * 设置两个子控件执行动画的间隔时间
         *
         * @param offset 间隔时间，单位ms
         * @return 构造器对象自身
         */
        public Builder offset(int offset) {
            this.startOffset = offset;
            return this;
        }

        /**
         * 设置每个子控件执行动画的执行时间
         *
         * @param duration 执行时间，单位ms
         * @return 构造器对象自身
         */
        public Builder duration(int duration) {
            this.duration = duration;
            return this;
        }

        /**
         * 设置第一个子控件执行动画的延迟时间
         *
         * @param delay 延迟时间，单位ms
         * @return 构造器对象自身
         */
        public Builder delay(int delay) {
            this.delay = delay;
            return this;
        }

        /**
         * 设置子控件执行动画的执行顺序
         *
         * @param direction 执行顺序，枚举类型
         * @return 构造器对象自身
         */
        public Builder flow(Direction direction) {
            this.direction = direction;
            return this;
        }

        /**
         * 设置每个子Component自定义动画对象,仅支持AnimatorProperty
         *
         * @param animator 自定义动画对象数组，按照顺序想对应布局内的每一个子Component
         * @return 构造器对象自身
         */
        public Builder anim(AnimatorProperty... animator) {
            this.animator = animator;
            return this;
        }

        /**
         * 设置每个子Component要执行的动画
         *
         * @param anim 要执行的动画，枚举
         * @return 构造器对象自身
         */
        public Builder anim(Animation anim) {
            this.anim = anim;
            return this;
        }

        /**
         * 开始执行动画
         *
         * @return Sequent对象
         */
        public Sequent start() {
            return new Sequent(this);
        }
    }

    /**
     * 创建Sequent构造器，绑定需要执行动画的布局
     *
     * @param vg 需要执行动画的布局
     * @return Sequent构造器
     */
    public static Builder origin(ComponentContainer vg) {
        return new Builder(vg);
    }

    private Sequent(Builder builder) {
        this.startOffset = builder.startOffset;
        this.duration = builder.duration;
        this.delay = builder.delay;
        this.direction = builder.direction;
        this.animator = builder.animator;
        this.anim = builder.anim;

        ComponentContainer vg = builder.vg;
        fetchChildLayouts(vg);
        arrangeLayouts(viewList);
        setAnimation();
    }

    private void fetchChildLayouts(ComponentContainer viewGroup) {
        int count = viewGroup.getChildCount();
        for (int i = 0; i < count; i++) {
            Component view = viewGroup.getComponentAt(i);
            if (view instanceof ComponentContainer) {
                fetchChildLayouts((ComponentContainer) view);
            } else {
                if (view.getVisibility() == Component.VISIBLE) {
                    view.setVisibility(Component.INVISIBLE);
                    viewList.add(view);
                }
            }
        }
    }

    private List<Component> arrangeLayouts(List<Component> viewList) {
        switch (direction) {
            case BACKWARD:
                Collections.reverse(viewList);
                break;
            case RANDOM:
                Collections.shuffle(viewList);
                break;
            default:
                break;
        }
        return viewList;
    }

    private void setAnimation() {
        int count = viewList.size();
        for (int i = 0; i < count; i++) {
            final Component view = viewList.get(i);
            final int offset = i * startOffset;
            resetAnimation(view);
            List<Animator> animatorList = new ArrayList<>();
            animatorList.add(getStartObjectAnimator(offset, view));

            if (animator != null && i < animator.length) {
                animator[i].setTarget(view);
                animatorList.add(animator[i]);
            } else if (anim != null) {
                animatorList.add(anim.getAnim(view));
            } else {
                animatorList.add(new AnimatorProperty().alphaFrom(0.0f).alpha(1.0f).setTarget(view));
            }
            AnimatorGroup animatorGroup = new AnimatorGroup();
            animatorGroup.setDuration(duration);
            if (animatorList.size() == 2) {
                animatorGroup.runParallel(animatorList.get(0), animatorList.get(1));
            }
            if (anim != null) {
                if (anim.getAnimId() == 1) {
                    animatorGroup.setCurveType(Animator.CurveType.SPRING);
                }
            }
            if (delay == 0) {
                animatorGroup.setDelay(i * startOffset);
            } else if (i == 0) {
                animatorGroup.setDelay(delay);
            } else {
                animatorGroup.setDelay((i * startOffset) + delay);
            }
            animatorGroup.start();
        }
    }

    private void resetAnimation(Component view) {
        view.setAlpha(1);
        view.setScaleX(1);
        view.setScaleY(1);
        view.setTranslationX(0);
        view.setTranslationY(0);
        view.setRotation(0);
    }

    private Animator getStartObjectAnimator(int offset, final Component view) {
        AnimatorProperty ob = new AnimatorProperty().alphaFrom(0.0f).alpha(1.0f).setTarget(view);
        ob.setDuration(1).setDelay(offset);
        ob.setStateChangedListener(new Animator.StateChangedListener() {
            @Override
            public void onStart(Animator animator) {
                view.setVisibility(Component.VISIBLE);
            }

            @Override
            public void onStop(Animator animator) {

            }

            @Override
            public void onCancel(Animator animator) {

            }

            @Override
            public void onEnd(Animator animator) {

            }

            @Override
            public void onPause(Animator animator) {

            }

            @Override
            public void onResume(Animator animator) {

            }
        });
        return ob;
    }

}
